package com.jwsoft.manager.core.dao.service.impl;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bifang.engine.assistant.core.exception.AppException;
import com.jwsoft.manager.common.enums.AreaEnum;
import com.jwsoft.manager.common.enums.DataSaveEnum;
import com.jwsoft.manager.common.vo.eduAddressTree.AddressBoundCheckVO;
import com.jwsoft.manager.common.vo.eduAddressTree.AddressTreeVO;
import com.jwsoft.manager.common.vo.eduAddressTree.EduAddressTreeVO;
import com.jwsoft.manager.core.dao.mapper.EduAddressMapper;
import com.jwsoft.manager.core.dao.mapper.EduAddressTreeMapper;
import com.jwsoft.manager.core.dao.model.EduAddress;
import com.jwsoft.manager.core.dao.model.EduAddressTree;
import com.jwsoft.manager.core.dao.service.EduAddressTreeService;
import com.jwsoft.manager.core.integration.eduAddressTree.TreeChangeHelper;
import com.jwsoft.manager.core.integration.eduAddressTree.impl.AddressTree;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务实现类
 *
 * @author fangs
 * @since 2023-02-03
 */
@Slf4j
@Service
public class EduAddressTreeServiceImpl extends ServiceImpl<EduAddressTreeMapper, EduAddressTree> implements EduAddressTreeService {

    /**
     * 地址链最大长度
     */
    private static final int CHAIN_MAX_LENGTH = 20;

    /**
     * 合并节点的最小节点数
     */
    private static final int MERGE_MIN_SIZE = 2;

    private static final String SEARCH_TERM_NAME = "searchTerm";

    private static final String FULL_ADDRESS_NAME = "fullAddress";

    private static final String EDU_ADDRESS_ID_NAME = "eduAddressId";

    private static final String IS_LEAF_NODE = "leafNode";


    @Autowired
    EduAddressMapper eduAddressMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void moveTreeNode(AddressTreeVO moveNode, AddressTreeVO target) {
        //先检查目标节点下是否有相同节点
        QueryWrapper<EduAddressTree> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(EduAddressTree::getParentId, target.getAddressId())
                .eq(EduAddressTree::getAreaName, moveNode.getAreaName());
        EduAddressTree eduAddressTree = getOne(queryWrapper);
        //如果没有则直接修改父节点
        if (eduAddressTree == null) {
            //修改节点
            update(new UpdateWrapper<EduAddressTree>()
                    .lambda()
                    .eq(EduAddressTree::getAddressId, moveNode.getAddressId())
                    .set(EduAddressTree::getParentId, target.getAddressId()));
            //检查目标节点是否是叶子节点，如果是改为不是
            if (target.getLastNode() == 1) {
                update(new UpdateWrapper<EduAddressTree>().lambda()
                        .eq(EduAddressTree::getAddressId, target.getAddressId())
                        .set(EduAddressTree::getLastNode, 0));
            }
            //检查之前的父节点是否还有子节点，没有则将lastNode改为1
            QueryWrapper<EduAddressTree> childCount = new QueryWrapper<>();
            childCount.lambda().eq(EduAddressTree::getParentId, moveNode.getParentId());
            if (count(queryWrapper) == 0) {
                update(new UpdateWrapper<EduAddressTree>().lambda()
                        .eq(EduAddressTree::getAddressId, moveNode.getParentId())
                        .set(EduAddressTree::getLastNode, 1));
            }
        } else {
            //目标节点下存在相同节点，进行合并
            AddressTreeVO addressTree = Convert.convert(AddressTreeVO.class, eduAddressTree);
            AddressTreeVO node = this.mergeNode(addressTree, moveNode);
            //保存合并后的节点
            Map<DataSaveEnum, List<EduAddressTreeVO>> saveData = node.getSaveData();
            applyMerge(saveData, null);
        }
    }

    @Override
    public List<AddressTreeVO> getAddressChain(Long leafId) {
        List<AddressTreeVO> list = new ArrayList<>();
        long id = leafId;
        int num = 0;
        do {
            EduAddressTree eduAddressTree = baseMapper.selectById(id);
            if (eduAddressTree == null) {
                return new ArrayList<>();
            }
            AddressTreeVO addressTreeVO = Convert.convert(AddressTreeVO.class, eduAddressTree);
            list.add(addressTreeVO);
            id = addressTreeVO.getParentId();
        } while (id > 0 && ++num <= CHAIN_MAX_LENGTH);
        return list;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveNewNode(EduAddressTree eduAddressTree) {
        //保存新节点
        baseMapper.insert(eduAddressTree);
        //修改上级节点为非末级节点
        UpdateWrapper<EduAddressTree> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(EduAddressTree::getAddressId, eduAddressTree.getParentId())
                .eq(EduAddressTree::getLastNode, 1)
                .set(EduAddressTree::getLastNode, 0)
                .set(EduAddressTree::getLeafNode, 0);
        baseMapper.update(null, updateWrapper);
    }

    @Override
    public AddressTreeVO mergeNode(AddressTreeVO majorNode, AddressTreeVO slaveNode) {
        List<AddressTreeVO> list = new ArrayList<>(2);
        list.add(majorNode);
        list.add(slaveNode);
        return mergeNode(list, 0);
    }

    @Override
    public AddressTreeVO mergeNode(List<AddressTreeVO> list, Integer masterIndex) {
        return mergeNode(list, masterIndex, isOneStreet(list));
    }

    @Override
    public AddressTreeVO mergeNode(List<AddressTreeVO> list, Integer masterIndex, Boolean isOneStreet) {
        if (CollectionUtils.isEmpty(list) || list.size() < MERGE_MIN_SIZE) {
            throw new AppException("合并节点至少需要2个节点");
        }
        //合并后需要删除的节点
        List<EduAddressTreeVO> deleteList = new ArrayList<>(list.size());
        //合并后需要修改的节点
        List<EduAddressTreeVO> updateList = new ArrayList<>(list.size());
        //取出主节点
        AddressTreeVO node = list.get(masterIndex);
        //需要合并的子节点
        List<AddressTreeVO> childTreeList = new ArrayList<>();
        //需要去查询数据库获取的子节点
        Set<Long> childIdSet = new HashSet<>(list.size());
        for (int i = 0; i < list.size(); i++) {
            AddressTreeVO addressTree = list.get(i);
            if (!CollectionUtils.isEmpty(addressTree.getChildNode())) {
                childTreeList.addAll(addressTree.getChildNode());
            } else {
                childIdSet.add(addressTree.getAddressId());
            }
            if (i == masterIndex) {
                continue;
            }
            node = this.mergeNodeProperty(node, addressTree);
            EduAddressTreeVO deleteVO = Convert.convert(EduAddressTreeVO.class, list.get(i));
            deleteList.add(deleteVO);
        }

        //子级节点合并
        //查询出所有子节点，当前节点对象中存在则从对象中获取，否则从数据库中获取
        QueryWrapper<EduAddressTree> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in(EduAddressTree::getParentId, childIdSet);
        List<EduAddressTree> childList = this.list(queryWrapper);
        if (!CollectionUtils.isEmpty(childList)) {
            childTreeList.addAll(Convert.toList(AddressTreeVO.class, childList));
        }
        //存放合并后的子节点
        List<AddressTreeVO> newChildList = new ArrayList<>();
        Map<String, List<AddressTreeVO>> childListGroup = childTreeList.stream().collect(Collectors.groupingBy(AddressTreeVO::getAreaName));
        for (String areaName : childListGroup.keySet()) {
            AddressTreeVO item;
            if (childListGroup.get(areaName).size() > 1) {
                List<AddressTreeVO> childNode = childListGroup.get(areaName);
                int majorIndex = 0;
                //找出属于主节点的子节点
                for (int i = 0; i < childNode.size(); i++) {
                    AddressTreeVO addressTree = childNode.get(i);
                    if (node.getAddressId().equals(addressTree.getParentId())) {
                        //以主节点为父节点的子节点为下级主节点进行合并
                        majorIndex = i;
                        break;
                    }
                }
                item = mergeNode(childListGroup.get(areaName), majorIndex, isOneStreet);
            } else {
                item = childListGroup.get(areaName).get(0);
                item.setSaveFlag(false);
            }
            if (!node.getAddressId().equals(item.getParentId())) {
                item.setParentId(node.getAddressId());
                item.setSaveFlag(true);
                //跨街道合并，则修改标记，在定时任务中进行处理
                if (!isOneStreet) {
                    item.setChangeNode(1);
                }
            }
            //如果子节点有变化，则将变化的数据设置到updateList中
            if (item.getSaveFlag()) {
                EduAddressTreeVO itemVO = Convert.convert(EduAddressTreeVO.class, item);
                updateList.add(itemVO);
            }
            //如果子节点有合并变动数据，则将变动数据设置到updateList中
            if (!CollectionUtils.isEmpty(item.getSaveData())) {
                Map<DataSaveEnum, List<EduAddressTreeVO>> childChangeData = item.getSaveData();
                for (DataSaveEnum dataSaveEnum : childChangeData.keySet()) {
                    switch (dataSaveEnum) {
                        case update:
                            updateList.addAll(childChangeData.get(dataSaveEnum));
                            break;
                        case delete:
                            deleteList.addAll(childChangeData.get(dataSaveEnum));
                            break;
                        default:
                            log.info("合并异常,出现未知的数据新增");
                            throw new AppException("合并异常");
                    }
                }
                //变动数据转移完成后，清空子节点的变动数据
                item.setSaveData(null);
            }
            newChildList.add(item);
        }
        node.setChildNode(newChildList);
        node.setSaveFlag(true);

        EduAddressTreeVO nodeVO = Convert.convert(EduAddressTreeVO.class, node);
        updateList.add(nodeVO);
        Map<DataSaveEnum, List<EduAddressTreeVO>> saveData = new HashMap<>((int) (2 / 0.75D + 1));
        saveData.put(DataSaveEnum.update, updateList);
        saveData.put(DataSaveEnum.delete, deleteList);
        node.setSaveData(saveData);
        return node;
    }

    @Override
    public AddressTreeVO mergeNodeAndCreateParent(List<AddressTreeVO> list) {
        if (CollectionUtils.isEmpty(list) || list.size() < 2) {
            throw new AppException("合并节点至少需要2个节点");
        }
        Long newNodeId = IdWorker.getId();
        Long oldParent = list.get(0).getParentId();
        //遍历所有节点，找出commonName
        String commonName = null;
        int minNameLength = Integer.MAX_VALUE;
        for (AddressTreeVO addressTree : list) {
            if (!StringUtils.hasText(addressTree.getAreaName())) {
                continue;
            }
            //记录最短的名称长度
            if (minNameLength > addressTree.getAreaName().length()) {
                minNameLength = addressTree.getAreaName().length();
            }
            if (commonName == null) {
                commonName = addressTree.getAreaName();
                continue;
            }
            if (addressTree.getAreaName().indexOf(commonName) == 0) {
                continue;
            }
            char[] chars = addressTree.getAreaName().toCharArray();
            char[] commonChars = commonName.toCharArray();
            int maxCommonIndex = -1;
            for (int i = 0; i < chars.length && i < commonChars.length; i++) {
                if (chars[i] == commonChars[i]) {
                    maxCommonIndex = i;
                } else {
                    break;
                }
            }
            if (maxCommonIndex == -1) {
                throw new AppException("当前集合名称没有共同的字段");
            }
            commonName = commonName.substring(0, maxCommonIndex + 1);
        }
        if (ObjectUtils.isEmpty(commonName)) {
            throw new AppException("当前集合名称没有共同的字段");
        }
        if (commonName.length() == minNameLength) {
            throw new AppException("当前集合中存在与抽取名称相同名称的节点");
        }
        //记录所有子节点的旧父节点id，将子节点的父节点id设置为新的父节点id
        for (AddressTreeVO node : list) {
            node.setAreaName(node.getAreaName().substring(commonName.length()));
            node.setParentId(newNodeId);
        }
        //创建父节点
        AddressTreeVO parent = new AddressTreeVO();
        parent.setMajorPointer(0L);
        parent.setAreaType(AreaEnum.other.getType());
        parent.setAreaName(commonName);
        parent.setSearchTerm(commonName);
        parent.setChildNode(list);
        parent.setParentId(oldParent);
        parent.setAddressId(newNodeId);
        parent.setLeafNode(0);
        parent.setLastNode(0);

        //设置变动数据
        Map<DataSaveEnum, List<EduAddressTreeVO>> saveData = new HashMap<>((int) (2 / 0.75D + 1));
        //将父节点设置为新增节点
        List<EduAddressTreeVO> insert = new ArrayList<>(1);
        EduAddressTreeVO eduAddressTreeVO = Convert.convert(EduAddressTreeVO.class, parent);
        insert.add(eduAddressTreeVO);
        saveData.put(DataSaveEnum.insert, insert);
        //将子节点设置为更新节点
        List<EduAddressTreeVO> update = Convert.toList(EduAddressTreeVO.class, list);
        saveData.put(DataSaveEnum.update, update);

        parent.setSaveData(saveData);
        return parent;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void applyMerge(Map<DataSaveEnum, List<EduAddressTreeVO>> saveData, Map<Long, Long> idMap) {
        if (idMap == null) {
            idMap = new HashMap<>();
        }
        insertMarge(saveData.get(DataSaveEnum.insert), idMap);
        updateMarge(saveData.get(DataSaveEnum.update), idMap);
        deleteMarge(saveData.get(DataSaveEnum.delete), idMap);
    }

    @Override
    public List<EduAddressTree> getChildrenById(Long addressId) {
        QueryWrapper<EduAddressTree> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(EduAddressTree::getParentId,addressId)
                .ne(EduAddressTree::getAreaType, "error")
                .eq(EduAddressTree::getMajorPointer,"0");
        return this.baseMapper.selectList(queryWrapper);
    }

    /**
     * 得到节点的链路信息  截止到 district 以下
     * 从下到上
     * @param treeId
     * @return
     */
    @Override
    public List<EduAddressTree> getLinkByTreeId(Long treeId) {
        ArrayList<EduAddressTree> linkIds = new ArrayList<>();
        EduAddressTree eduAddressTree = baseMapper.selectById(treeId);
        if (eduAddressTree == null) {
            return linkIds;
        }
        ArrayList<String> areaTypeList = new ArrayList<>();
        areaTypeList.add("country");
        areaTypeList.add("province");
        areaTypeList.add("city");
        areaTypeList.add("district");
        if (org.apache.commons.lang3.StringUtils.isBlank(eduAddressTree.getAreaType())){
            throw new AppException("节点类型错误");
        }
        while (!areaTypeList.contains(eduAddressTree.getAreaType())) {
            linkIds.add(eduAddressTree);
            QueryWrapper<EduAddressTree> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda()
                    .eq(EduAddressTree::getAddressId, eduAddressTree.getParentId());
            eduAddressTree = baseMapper.selectOne(queryWrapper);
            if(eduAddressTree == null){
                break;
            }

        }
        return linkIds;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changeDown(EduAddressTree eduAddressTree) {
        if (eduAddressTree.getLeafNode() == 0 || eduAddressTree.getLastNode() == 0) {
            UpdateWrapper<EduAddressTree> childUpdate = new UpdateWrapper<>();
            childUpdate.lambda().eq(EduAddressTree::getParentId, eduAddressTree.getAddressId())
                    .set(EduAddressTree::getChangeNode, 1);
            baseMapper.update(null, childUpdate);
        }

        if (eduAddressTree.getChangeNode() == 1) {
            UpdateWrapper<EduAddressTree> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().eq(EduAddressTree::getAddressId, eduAddressTree.getAddressId())
                    .set(EduAddressTree::getChangeNode, 0);
            baseMapper.update(null, updateWrapper);
        }
    }

    @Override
    public Boolean isOneStreet(List<AddressTreeVO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return true;
        }
        if (list.size() == 1) {
            return true;
        }
        Map<String, List<AddressTreeVO>> collect = list.stream().collect(Collectors.groupingBy(AddressTreeVO::getAreaType));
        if (collect.containsKey(AreaEnum.district.getType()) || collect.containsKey(AreaEnum.city.getType())
                || collect.containsKey(AreaEnum.province.getType()) || collect.containsKey(AreaEnum.town.getType())) {
            return false;
        }
        Set<Long> parentIds = list.stream().map(AddressTreeVO::getParentId).collect(Collectors.toSet());
        if (parentIds.size() == 1) {
            return true;
        }
        Set<String> streetSet = new HashSet<>();
        for (Long parentId : parentIds) {
            AddressTree addressTree = AddressTree.getAddressTree();
            addressTree.populate(parentId);
            if (streetSet.add(addressTree.getStreetCode())) {
                if (streetSet.size() > 1) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 根据行政区划，得到树节点信息
     * @param provinceCode
     * @return
     */
    @Override
    public EduAddressTree getAddressByAreaCode(String provinceCode) {
        QueryWrapper<EduAddressTree> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(EduAddressTree::getAreaCode,provinceCode)
                .ne(EduAddressTree::getAreaType, "error")
                .eq(EduAddressTree::getMajorPointer, "0");
        return  this.getOne(queryWrapper);
    }

    @Override
    public List<AddressBoundCheckVO> queryBoundLessAsLeafNodes(String areaType, Integer mixNum, Long parentId, String schoolId) {
        List<AddressBoundCheckVO> addressBoundCheckVOS = eduAddressMapper.queryBoundLessAsLeafNodes(areaType, mixNum,parentId,schoolId);
        return addressBoundCheckVOS;
    }

    @Override
    public List<AddressBoundCheckVO> queryBoundLeafNode(Long treeId, String schoolId) {
        List<AddressBoundCheckVO> addressBoundCheckVOS = eduAddressMapper.queryBoundLeafNode(treeId,schoolId);
        return addressBoundCheckVOS;
    }

    /**
     * 根据树节点链路信息进行删除
     * @param treeNodes 树节点链路
     */
    @Override
    public void removeByTreeLink(List<EduAddressTree> treeNodes) {
        if (treeNodes == null || treeNodes.size() == 0){
            return;
        }
        for (int i = 0; i < treeNodes.size(); i++){
            EduAddressTree treeNode = treeNodes.get(i);
            if (treeNode != null){
                //删除树节点信息
                removeById(treeNode.getAddressId());
            }
            //判断父级节点是否能进行删除，根据父节点判断是否还有子节点
            if (ObjectUtils.isEmpty(treeNode.getParentId())){
                return;
            }
            QueryWrapper<EduAddressTree> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(EduAddressTree::getParentId,treeNode.getParentId());
            if (count(queryWrapper) > 0){
                return;
            }
        }
    }

    @Override
    public List<EduAddressTree> getAllDescendants(Long treeId) {
        List<EduAddressTree> descendants = new ArrayList<>();
        //获取id的直接子级节点
        List<EduAddressTree> childNodes = list(Wrappers.<EduAddressTree>lambdaQuery()
                .select(EduAddressTree::getAddressId).eq(EduAddressTree::getParentId, treeId));
        if (CollectionUtils.isEmpty(childNodes)){
            return descendants;
        }
        for (EduAddressTree childNode : childNodes) {
            //获取子级节点的子级节点
           descendants.add(childNode);
           List<EduAddressTree> grandchildren = getAllDescendants(childNode.getAddressId());
           descendants.addAll(grandchildren);
        }
        return descendants;
    }

    @Override
    public List<EduAddress> getAddressByTreeId(List<Long> treeIds) {
        ArrayList<EduAddress> result = new ArrayList<>();
        QueryWrapper<EduAddress> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .in(EduAddress::getAddressTreeId, treeIds);
        if (eduAddressMapper.selectCount(queryWrapper) > 0){
            queryWrapper.lambda()
                    .select(EduAddress::getAddressId,EduAddress::getAddressTreeId,EduAddress::getAddressName);
            result.addAll(eduAddressMapper.selectList(queryWrapper));
        }
        return result;
    }

    /**
     * 插入合并数据
     *
     * @param insertList 需要插入的数据
     * @param idMap      应用前的id和应用后的id的映射
     * @author fangs
     */
    void insertMarge(List<EduAddressTreeVO> insertList, Map<Long, Long> idMap) {
        if (CollectionUtils.isEmpty(insertList)) {
            return;
        }
        //排序，主键小的排前面
        insertList = insertList.stream().sorted(new Comparator<EduAddressTreeVO>() {
            @Override
            public int compare(EduAddressTreeVO o1, EduAddressTreeVO o2) {
                return o1.getAddressId().compareTo(o2.getAddressId());
            }
        }).collect(Collectors.toList());
        for (EduAddressTreeVO addressTreeVO : insertList) {
            if (idMap.containsKey(addressTreeVO.getParentId())) {
                addressTreeVO.setParentId(idMap.get(addressTreeVO.getParentId()));
            }
            Long idKey = addressTreeVO.getAddressId();
            addressTreeVO.setAddressId(null);
            EduAddressTree eduAddressTree = Convert.convert(EduAddressTree.class, addressTreeVO);
            //设置变成状态为1，表示需要节点本身或者子节点关联的地址数据需要更新
            eduAddressTree.setChangeNode(1);
            save(eduAddressTree);
            //保存改变的树节点，后续进行关联变更
            addressTreeVO.setChangeType(DataSaveEnum.insert);
            addressTreeVO.setAddressId(eduAddressTree.getAddressId());
            TreeChangeHelper.addTreeChange(addressTreeVO);
            if (!ObjectUtils.isEmpty(idKey)) {
                idMap.put(idKey, eduAddressTree.getAddressId());
            }
        }
    }

    void updateMarge(List<EduAddressTreeVO> updateList, Map<Long, Long> idMap) {
        if (CollectionUtils.isEmpty(updateList)) {
            return;
        }
        for (EduAddressTreeVO addressTreeVO : updateList) {
            if (idMap.containsKey(addressTreeVO.getParentId())) {
                addressTreeVO.setParentId(idMap.get(addressTreeVO.getParentId()));
            }
            if (idMap.containsKey(addressTreeVO.getAddressId())) {
                addressTreeVO.setAddressId(idMap.get(addressTreeVO.getAddressId()));
            }
            //保存改变的树节点，后续进行关联变更
            QueryWrapper<EduAddressTree> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().select(EduAddressTree::getAddressId, EduAddressTree::getParentId)
                    .eq(EduAddressTree::getAddressId, addressTreeVO.getAddressId());
            EduAddressTree eduAddressTree = getOne(queryWrapper);
            if (eduAddressTree == null) {
                continue;
            }
            addressTreeVO.setOldParentId(eduAddressTree.getParentId());
            addressTreeVO.setChangeType(DataSaveEnum.update);
            TreeChangeHelper.addTreeChange(addressTreeVO);
            UpdateWrapper<EduAddressTree> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().eq(EduAddressTree::getAddressId, addressTreeVO.getAddressId())
                    .set(EduAddressTree::getParentId, addressTreeVO.getParentId())
                    .set(EduAddressTree::getSearchTerm, addressTreeVO.getSearchTerm())
                    .set(EduAddressTree::getLastNode, addressTreeVO.getLastNode())
                    .set(EduAddressTree::getLeafNode, addressTreeVO.getLeafNode())
                    .set(EduAddressTree::getAreaName, addressTreeVO.getAreaName())
                    .set(EduAddressTree::getFullAddress, addressTreeVO.getFullAddress())
                    .set(EduAddressTree::getEduAddressId, addressTreeVO.getEduAddressId())
                    .set(EduAddressTree::getChangeNode, addressTreeVO.getChangeNode());
            update(updateWrapper);
        }
    }

    void deleteMarge(List<EduAddressTreeVO> deleteList, Map<Long, Long> idMap) {
        if (CollectionUtils.isEmpty(deleteList)) {
            return;
        }
        for (EduAddressTreeVO addressTreeVO : deleteList) {
            if (idMap.containsKey(addressTreeVO.getAddressId())) {
                addressTreeVO.setAddressId(idMap.get(addressTreeVO.getAddressId()));
            }
            addressTreeVO.setChangeType(DataSaveEnum.delete);
            TreeChangeHelper.addTreeChange(addressTreeVO);
        }
        Set<Long> deleteIds = deleteList.stream().map(EduAddressTreeVO::getAddressId).collect(Collectors.toSet());
        removeBatchByIds(deleteIds);
    }


    /**
     * 合并2个节点
     *
     * @param majorNode 合并主节点，该节点中的属性不会被覆盖，会用从节点属性补充该节点为空的数据
     * @param slaveNode 合并从节点，补充主节点为空的数据
     * @return 合并后的节点
     * @author fangs
     */
    private AddressTreeVO mergeNodeProperty(AddressTreeVO majorNode, AddressTreeVO slaveNode) {
        //合并检索项数据
        Map<String, Object> majorMap = Convert.toMap(String.class, Object.class, majorNode);
        Map<String, Object> slaveMap = Convert.toMap(String.class, Object.class, slaveNode);
        Set<String> keys = new HashSet<>(majorMap.keySet());
        keys.addAll(slaveMap.keySet());
        for (String key : keys) {
            //处理检索项 searchTerm
            if (SEARCH_TERM_NAME.equals(key)) {
                Set<String> searchTermSet = new HashSet<>();
                String majorSearch = (String) majorMap.get(key);
                String slaveSearch = (String) slaveMap.get(key);
                if (StringUtils.hasText(majorSearch)) {
                    searchTermSet.addAll(Arrays.asList(majorSearch.split(AddressTree.SEARCH_TERM_SEPARATOR)));
                }
                if (StringUtils.hasText(slaveSearch)) {
                    searchTermSet.addAll(Arrays.asList(slaveSearch.split(AddressTree.SEARCH_TERM_SEPARATOR)));
                }
                //将2个节点的名称设置进入searchTerm
                searchTermSet.add(majorNode.getAreaName());
                searchTermSet.add(slaveNode.getAreaName());
                StringBuilder searchSb = new StringBuilder();
                searchTermSet.forEach(item -> {
                    if (searchSb.length() > 0) {
                        searchSb.append(AddressTree.SEARCH_TERM_SEPARATOR);
                    }
                    searchSb.append(item);
                });
                majorMap.put(key, searchSb.toString());
                continue;
            }
            //处理完整地址信息
            if (FULL_ADDRESS_NAME.equals(key) || EDU_ADDRESS_ID_NAME.equals(key)) {
                if (StringUtils.hasText((CharSequence) majorMap.get(key)) && StringUtils.hasText((CharSequence) slaveMap.get(key))) {
                    StringJoiner newFullAddress = new StringJoiner(",");
                    newFullAddress.add((CharSequence) majorMap.get(key))
                            .add((CharSequence) slaveMap.get(key));
                    majorMap.put(key, newFullAddress.toString());
                    continue;
                }
            }
            //处理是否叶子节点属性
            if (IS_LEAF_NODE.equals(key)) {
                if (!slaveMap.containsKey(key) || slaveMap.get(key) == null) {
                    continue;
                }
                Integer leafNode = (Integer) slaveMap.get(key);
                if (leafNode == 1) {
                    majorMap.put(key, 1);
                }
                continue;
            }

            //如果主节点不存在该属性则用从节点填充
            if (!majorMap.containsKey(key) || majorMap.get(key) == null) {
                majorMap.put(key, slaveMap.get(key));
            }
        }
        majorNode = Convert.convert(AddressTreeVO.class, majorMap);
        return majorNode;
    }
}
